/**
 * Copyright 2004 - 2007 Blue Bamboo International Inc. 
 *           All rights reserved.
 *
 *
 * Blue Bamboo PROPRIETARY/CONFIDENTIAL.
 *
 */

package com.bluebamboo.bluetools.pingpang.ui;

import java.util.Collection;
import java.util.HashSet;

import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.TrayDialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;

import com.bluebamboo.bluetools.common.ui.utils.SWTFactory;
import com.bluebamboo.bluetools.pingpang.bean.ConnectionBean;
import com.bluebamboo.bluetools.pingpang.bean.ConnectionBeanManager;

/**
 * DOCME
 * 
 * @author Nick.Tan
 * 
 */
public class ConnectDialog extends TrayDialog {

	private TreeViewer connectionViewer;
	private Button editButton;
	private Button addButton;
	private Button removeButton;
	private ConnectionBeanManager beanMgr;
	private ConnectionBean currentConnBean;

	/**
	 * @param shell
	 */
	protected ConnectDialog(Shell shell) {
		super(shell);
	}

	@Override
	protected void configureShell(Shell newShell) {
		super.configureShell(newShell);
	}

	@Override
	protected Control createContents(Composite parent) {
		getShell().setText(Messages.getString(Messages.ConnectDialog_title));
		return super.createContents(parent);
	}

	@Override
	protected Control createDialogArea(Composite parent) {
		Composite container = SWTFactory.createComposite(parent, parent.getFont(), 2, 1, GridData.FILL_BOTH, 0, 0);
		createConnectionArea(container);
		createButtonArea(container);

		initWidgetValues();
		return container;
	}

	private void createConnectionArea(Composite parent) {
		Composite container = SWTFactory.createComposite(parent, 1, GridData.FILL_BOTH);
		Tree tree = new Tree(container, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL | SWT.H_SCROLL);
		int widthHint = convertWidthInCharsToPixels(36);
		int heigthHint = convertHeightInCharsToPixels(10);
		GridDataFactory.fillDefaults().grab(true, true).hint(widthHint, heigthHint).applyTo(tree);
		connectionViewer = new TreeViewer(tree);
		connectionViewer.setContentProvider(new ConnectionContentProvider());
		connectionViewer.setLabelProvider(new ConnectionLabelProvider());

		connectionViewer.addSelectionChangedListener(new ISelectionChangedListener() {

			public void selectionChanged(SelectionChangedEvent event) {
				currentConnBean = getSelectedConnectionBean();
				updateButtons();
			}
		});
	}

	private void createButtonArea(Composite parent) {
		Composite container = SWTFactory.createComposite(parent, 1, GridData.FILL_VERTICAL);

		addButton = SWTFactory.createPushButton(container, "Add");
		editButton = SWTFactory.createPushButton(container, "Edit");
		removeButton = SWTFactory.createPushButton(container, "Remove");

		addButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				handleAddConnection();
			}
		});
		editButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				handleEditConnection();
			}
		});
		removeButton.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				handleRemoveConnection();
			}
		});
	}

	private void initWidgetValues() {
		beanMgr = ConnectionBeanManager.getInstance();
		connectionViewer.setInput(beanMgr.listConnections());
		connectionViewer.expandAll();
	}

	private void updateButtons() {
		if (currentConnBean == null) {
			editButton.setEnabled(false);
			removeButton.setEnabled(false);
		}
		else {
			editButton.setEnabled(true);
			removeButton.setEnabled(true);
		}
	}

	ConnectionBean getSelectedConnectionBean() {
		IStructuredSelection ssl = (IStructuredSelection) connectionViewer.getSelection();
		Object obj = ssl.getFirstElement();
		if (obj == null || !(obj instanceof ConnectionBean))
			return null;
		return (ConnectionBean) obj;
	}

	@Override
	protected void createButtonsForButtonBar(Composite parent) {
		createButton(parent, IDialogConstants.OK_ID, "Connect", true);
		createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
	}

	@Override
	protected void buttonPressed(int buttonId) {
		super.buttonPressed(buttonId);
	}

	private void handleAddConnection() {

	}

	private void handleEditConnection() {

	}

	private void handleRemoveConnection() {

	}

	public ConnectionBean getConnectionBean() {
		return currentConnBean;
	}

	private class ConnectionContentProvider implements ITreeContentProvider {

		private Collection<ConnectionBean> conns;

		public Object[] getChildren(Object parentElement) {
			if (parentElement instanceof ConnectionGroup) {
				ConnectionGroup g = (ConnectionGroup) parentElement;
				HashSet<ConnectionBean> beans = new HashSet<ConnectionBean>();
				for (ConnectionBean bean : conns) {
					if (bean.getType() == g.getType()) {
						beans.add(bean);
					}
				}
				return beans.toArray(new ConnectionBean[beans.size()]);
			}
			return new Object[0];
		}

		public Object getParent(Object element) {
			// TODO Auto-generated method stub
			return null;
		}

		public boolean hasChildren(Object element) {
			return getChildren(element).length > 0;
		}

		public Object[] getElements(Object inputElement) {
			conns = (Collection<ConnectionBean>) inputElement;
			HashSet<ConnectionGroup> groups = new HashSet<ConnectionGroup>();
			for (ConnectionBean bean : conns) {
				String name = "UNKNOWN";
				switch (bean.getType()) {
				case ConnectionBean.TYPE_SERIAL:
					name = "serial";
					break;
				case ConnectionBean.TYPE_TCP_CLIENT:
				case ConnectionBean.TYPE_TCP_SERVER:
					name = "tcp";
					break;
				case ConnectionBean.TYPE_UDP_CLIENT:
				case ConnectionBean.TYPE_UDP_SERVER:
					name = "udp";
					break;
				default:
					break;
				}
				ConnectionGroup g = new ConnectionGroup(bean.getType(), name);
				groups.add(g);
			}
			return groups.toArray(new ConnectionGroup[groups.size()]);
		}

		public void dispose() {
		}

		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		}

	}

	private class ConnectionLabelProvider extends LabelProvider {
		@Override
		public String getText(Object element) {
			if (element instanceof ConnectionGroup)
				return ((ConnectionGroup) element).getName();
			else if (element instanceof ConnectionBean) {
				return ((ConnectionBean) element).getName();
			}
			return element.toString();
		}
	}

	private static class ConnectionGroup {
		public int type;
		public String name;

		public ConnectionGroup(int type, String name) {
			super();
			this.type = type;
			this.name = name;
		}

		protected int getType() {
			return type;
		}

		protected void setType(int type) {
			this.type = type;
		}

		protected String getName() {
			return name;
		}

		protected void setName(String name) {
			this.name = name;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + ((name == null) ? 0 : name.hashCode());
			result = prime * result + type;
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			ConnectionGroup other = (ConnectionGroup) obj;
			if (name == null) {
				if (other.name != null)
					return false;
			}
			else if (!name.equals(other.name))
				return false;
			if (type != other.type)
				return false;
			return true;
		}

	}
}
